<?php

namespace xingwu;

use think\exception\HttpException;

class Xingwu
{
    protected $host = 'https://guanj.51wanquan.com';

    //中军昆仑摩派广东智能科技有限公司
    protected $mchid = '1639723593';//翼龙商户号
    protected $signKey = 'SnHIPQG592vJcQnxbFhLT1LRZ91Oxcfm';//签名秘钥

    public function __construct() {
        $config = config('thirdpay.xingwu');
        $this->mchid = $config['mchid'];
        $this->signKey = $config['signKey'];
        $this->host = $config['host'];
    }
    /**
     * [login 登录]
     * @since  2022-09-24
     * @param  [type]     $mchid           [翼龙商户号]
     * @param  [type]     $account         [营业员登录账号]
     * @param  [type]     $pwd          [密码]
     * @param  [type]     $apikey [API密钥]
     * @param  [type]     $refreshToken  [description]
     * @return [type]                     [description]
     */
    public function login($account,$pwd,$refreshToken = '')
    {
        $api = $this->host.'/merchant/clerk/login';
        $json = [
            'mchid'=>$this->mchid  ,// 翼龙商户号
            'account'=>$account  ,// 营业员登录账号
            // 'pwd'=>strtolower( md5($pwd))   ,// 按照 md5(md5(pwd)连接上pwd) 获得的32为小写MD5串
            'pwd'=>strtolower(md5( md5($pwd).$pwd) )  ,// 按照 md5(md5(pwd)连接上pwd) 获得的32为小写MD5串
            'refreshToken'=>$refreshToken === true?'true':strtolower($refreshToken),//  是否更新用户token（更新后旧 token 将立即失效）；更新值为小写 true，否则不更新
        ];
        return $this->exec($api,$json);
    }
    /**
     * [qr_pay 支付宝动码]
     * @since  2022-09-24
     * @param  [type]     $mchid           [翼龙商户号]
     * @param  [type]     $storeCode         [门店code]
     * @param  [type]     $money          [订单金额（单位：元）]
     * @param  [type]     $apikey [API密钥]
     * @return [type]                     [description]
     */
    public function qr_pay($storeCode,$money,$outMerchantOrderNo = '',$remark='',$notify_url='',$isNeedShare='2')
    {
        $api = $this->host.'/merchant/pay/qr_pay';
        $json = [
            'mchid'=>$this->mchid  ,// 翼龙商户号
            'storeCode'=>$storeCode  ,// 门店code
            'totalFee'=>floatval($money)  ,// 订单金额（单位：元）
            'outMerchantOrderNo'=>$outMerchantOrderNo,//  外部商户订单号（建议上传）
            'isNeedShare'=>$isNeedShare,//  是否为分账订单(详见下面说明)
            // 重要提醒 isNeedShare 当前是专门针对我司上游通道为盛付通新API下的商户定制使用，其他商户请勿使用。此范围内的商户对接时请注意：
            // 前置条件
            // 商户具有分账权限
            // 对应交易门店已完成分账配置（如未完成，请至「商户后台」完成相关配置）

            // isNeedShare 值说明
            // 1 商户自主分账的交易，需要参照「 商户自主分账 」章节完成相关分账对接，否则资金无法自动结算到账户
            // 2 翼龙支付系统自动分账的交易，将由我司分账服务于交易次日自动进行分账
            // 0 或 无此参数 不支持分账，资金将结算给收单户
            'remark'=>$remark,//  备注
            'notify_url'=>$notify_url,//  支付后回调通知地址（URL encode后参与签名）
        ];
        return $this->exec($api,$json);
    }
    /**
     * [qrcode_pay C扫B支付]
     * @since  2022-09-24
     * @param  [type]     $mchid           [翼龙商户号]
     * @param  [type]     $storeCode         [门店code]
     * @param  [type]     $money          [订单金额（单位：元）]
     * @param  [type]     $apikey [API密钥]
     * @return [type]                     [description]
     */
    public function qrcode_pay($token,$money,$outMerchantOrderNo = '',$notify_url='',$isNeedShare='2')
    {
        $api = $this->host.'/merchant/pay/qrcode_pay';


        $json = [
            'mchid'=>$this->mchid  ,// 翼龙商户号
            'token'=>$token  ,// 营业员登录Token
            'totalFee'=>floatval($money)  ,// 订单金额（单位：元）
            // 'appid'=>$appid  ,// 微信小程序APPID
            // 'openid'=>$openid  ,// 上述微信小程序下的客户openid
            'outMerchantOrderNo'=>$outMerchantOrderNo,//  外部商户订单号（建议上传）
            'isNeedShare'=>$isNeedShare,//  是否为分账订单(详见下面说明)
            // 重要提醒 isNeedShare 当前是专门针对我司上游通道为盛付通新API下的商户定制使用，其他商户请勿使用。此范围内的商户对接时请注意：
            // 前置条件
            // 商户具有分账权限
            // 对应交易门店已完成分账配置（如未完成，请至「商户后台」完成相关配置）

            // isNeedShare 值说明
            // 1 商户自主分账的交易，需要参照「 商户自主分账 」章节完成相关分账对接，否则资金无法自动结算到账户
            // 2 翼龙支付系统自动分账的交易，将由我司分账服务于交易次日自动进行分账
            // 0 或 无此参数 不支持分账，资金将结算给收单户
            // 'remark'=>$remark,//  备注
            'notify_url'=>$notify_url,//  支付后回调通知地址（URL encode后参与签名）
            // 'terminalNo'=>$storeCode  ,// 不再使用，由通用参数 sn 代替
            // 'undiscountFee'=>$storeCode  ,// 不可打折金额（向下兼容保留）
        ];
        return $this->exec($api,$json);
    }
    /**
     * [mini_program_pay 微信小程序支付]
     * @since  2022-09-24
     * @param  [type]     $mchid           [翼龙商户号]
     * @param  [type]     $storeCode         [门店code]
     * @param  [type]     $money          [订单金额（单位：元）]
     * @param  [type]     $apikey [API密钥]
     * @return [type]                     [description]
     */
    public function mini_program_pay($token,$money,$outMerchantOrderNo = '',$notify_url='',$appid,$openid,$isNeedShare='2')
    {
        $api = $this->host.'/merchant/pay/mini_program_pay';
        $json = [
            'mchid'=>$this->mchid  ,// 翼龙商户号
            'token'=>$token  ,// 营业员登录Token
            'totalFee'=>sprintf('%.2f',$money)  ,// 订单金额（单位：元）
            'appid'=>$appid  ,// 微信小程序APPID
            'openid'=>$openid  ,// 上述微信小程序下的客户openid
            'outMerchantOrderNo'=>$outMerchantOrderNo,//  外部商户订单号（建议上传）
            'isNeedShare'=>$isNeedShare,//  是否为分账订单(详见下面说明)
            // 重要提醒 isNeedShare 当前是专门针对我司上游通道为盛付通新API下的商户定制使用，其他商户请勿使用。此范围内的商户对接时请注意：
            // 前置条件
            // 商户具有分账权限
            // 对应交易门店已完成分账配置（如未完成，请至「商户后台」完成相关配置）

            // isNeedShare 值说明
            // 1 商户自主分账的交易，需要参照「 商户自主分账 」章节完成相关分账对接，否则资金无法自动结算到账户
            // 2 翼龙支付系统自动分账的交易，将由我司分账服务于交易次日自动进行分账
            // 0 或 无此参数 不支持分账，资金将结算给收单户
            // 'remark'=>$remark,//  备注
            'notify_url'=>$notify_url,//  支付后回调通知地址（URL encode后参与签名）
            // 'terminalNo'=>$storeCode  ,// 不再使用，由通用参数 sn 代替
            // 'undiscountFee'=>$storeCode  ,// 不可打折金额（向下兼容保留）
        ];
        return $this->exec($api,$json);
    }
    /**
     * [query_order 订单轮询]
     * @since  2022-09-24
     * @param  [type]     $mchid           [翼龙商户号]
     * @param  [type]     $token         [营业员登录Token]
     * @param  [type]     $orderNo          [翼龙订单号]
     * @param  [type]     $apikey [API密钥]
     * @return [type]                     [description]
     */
    public function query_order($token,$orderNo)
    {
        $api = $this->host.'/merchant/pay/query_order';
        $json = [
            'mchid'=>$this->mchid  ,// 翼龙商户号
            'token'=>$token  ,// 营业员登录Token
            'orderNo'=> $orderNo ,// 翼龙订单号
        ];
        return $this->exec($api,$json);
    }
    /**
     * [notifySign 回调签名验证]
     * @since  2022-09-26
     * @param  string     $value              [description]
     * @param  [type]     $orderSelfNotifyKey [description]
     * @return [type]                         [description]
     */
    public static function notifySign($params,$orderSelfNotifyKey)
    {
        $signStr = '';
        ksort($params);
        foreach ($params as $key => $val) {
            if ($val === '' || $val === null || is_array($val) || $key =='sign') {
                continue;
            }
            $signStr .= ($signStr ? '&' : '') . "{$key}={$val}";
        }
        $signStrWithKey = $signStr . '&key=' . $orderSelfNotifyKey;
        return hash_hmac('md5', $signStrWithKey, $orderSelfNotifyKey);
    }

    protected function exec($api,$json)
    {
        $res = ['code'=>0,'msg'=>''];
        try {
            $param = $this->sign($json,$this->signKey);
            // var_dump($this->signKey);exit;
        } catch (HttpException $e) {
            $res['msg'] = $e->getMessage();
            return $res;
        }
        // parse_str($param, $paramArr);
        // $timestamp = $paramArr['timestamp'];
        // unset($paramArr['timestamp']);
        // $paramArr = array_merge(['timestamp'=>$timestamp],$paramArr);
        // var_dump($paramArr);exit;
        // \think\Log::info($param);
        // $param = http_build_query($paramArr);
        $httpRes = $this->curl_post($api,$param);
        // echo '请求URL:'.$api."\n";
        // echo '请求参数:'.$param."\n";
        // echo '响应内容:'.$httpRes[0]."\n";exit;

        if (empty($httpRes[0])) {
            $res['msg'] = '请求支付失败';
            return $res;
        }
        $arr = json_decode($httpRes[0],true);
        $res['data'] = $arr;
        // var_dump($arr);exit;
        if ($arr['status'] != 'SUCCESS') {
            $res['msg'] = $arr['errMsg'];
            return $res;
        }

        return ['code'=>1,'msg'=>'','data'=>$arr];
    }
    protected function curl_post($url,$uriParam)
    {
        $curl = curl_init(); // 启动一个CURL会话
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); // 从证书中检查SSL加密算法是否存在
        // curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器 使用命令不执行
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
        curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
        // curl_setopt($curl, CURLOPT_POSTFIELDS,json_encode($uriParam)); // Post提交的数据包
        curl_setopt($curl, CURLOPT_POSTFIELDS,is_array($uriParam)? http_build_query($uriParam):$uriParam); // Post提交的数据包
        // curl_setopt($curl, CURLOPT_POSTFIELDS,$uriParam); // Post提交的数据包
        curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
        curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
        // curl_setopt($curl, CURLOPT_HTTPHEADER,['Content-type:application/json']); // 设置头部
        curl_setopt($curl, CURLOPT_HTTPHEADER,['Content-type:application/x-www-form-urlencoded']); // 设置头部
        $res = curl_exec($curl); // 执行操作
        $errno = curl_errno($curl);
        curl_close($curl); // 关闭CURL会话
        return [$res,$errno];
    }
    protected function sign(array $params, string $signKey): string {
        // 兼容 notify_url URL ENCODE 问题，强制签名时该字符串必须是 URL ENCODE 后的字符串
        if (isset($params['notify_url']) && !empty($params['notify_url']) && preg_match("#^https?://#", $params['notify_url'])) {
            $params['notify_url'] = urlencode($params['notify_url']);
        }
        $params['timestamp']= (string)time();
        $params['nonceStr']= uniqid(). rand(1,9999);
        $params['channel']= 'API';
        $signStr = '';
        ksort($params);
        foreach ($params as $key => $val) {
            if ($val === '' || $val === null || is_array($val)) {
                continue;
            }
            $signStr .= ($signStr ? '&' : '') . "{$key}={$val}";
        }
        $signStrWithKey = $signStr . '&key=' . $signKey;
        $signHash = md5($signStrWithKey);
        // $signHash = hash_hmac('md5', $signStrWithKey, $signKey);
        // $signHash = hash_hmac('md5', $signStrWithKey, $signKey);
        // $signHash = hash_hmac('sha256', $signStrWithKey, $signKey);
        return $signStr.'&sign='.strtoupper($signHash);
        // parse_str($signStr,$a);
        // var_dump($a);
        // var_dump(explode('&', $signStr));
        exit;
        return $signStr.'&sign='.strtoupper($signHash);
        return 'timestamp='.$params['timestamp'].$signStr.'&sign='.strtoupper($signHash);
    }
    // protected function signMd5(array $params, string $signKey): string {
    //     // 兼容 notify_url URL ENCODE 问题，强制签名时该字符串必须是 URL ENCODE 后的字符串
    //     if (isset($params['notify_url']) && !empty($params['notify_url']) && preg_match("#^https?://#", $params['notify_url'])) {
    //         $params['notify_url'] = urlencode($params['notify_url']);
    //     }
    //     $signStr = '';
    //     ksort($params);
    //     foreach ($params as $key => $val) {
    //         if ($val === '' || $val === null || is_array($val)) {
    //             continue;
    //         }
    //         $signStr .= ($signStr ? '&' : '') . "{$key}={$val}";
    //     }
    //     $signStrWithKey = $signStr . '&key=' . $signKey;
    //     $signHash = hash_hmac('sha256', $signStrWithKey, $signKey);
    //     return $signStr.'&sign='.strtoupper($signHash);
    // }
}
